<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <!-- 
        父子组件之间进行双向通信的方法之二：

        1.使用

        在 vue 中，通常父子组件通信，我们使用的是 props，但是有的场景，我们需要对父子组件进行双向绑定。这时我们会用到 v-model 自定义组件。
        官网的解释则是，父组件将值通过 v-model 进行绑定，之后子组件通过 props 的 key 为 value 进行接收，然后通过默认事件 input 触发更改父组件。
        当然为了避免子组件内有 data，或其他 props 名为 value，所以在当前实例下，有一个 model 属性,定义方法如下：

        model: {
            prop: 'checked', // props默认是value
            event: 'change' // 事件名默认是input
        },

        这样在子组件内通过 $emit 触发定义好的 model 事件名更改父组件的值。

        在下面的例子中，根据 model 中的定义，v-model="num" 表明父组件中的 num 会和子组件中的 val 进行绑定，当父组件中的 num 值发生相应的变化
        时，子组件中的 val 也会发生相应的变化，这就实现了父组件到子组件的通信。然后子组件通过 this.$emit('input', newValue) 同步 v-model 的值，
        这就实现了子组件到父组件之间的通信。

        2.原理

        可以使用 v-model 来进行父子组件的通信，本质上是因为 v-model 是一个语法糖，它的原理和通信方法一一模一样。在父子组件的通信中，为了防止子组件
        不小心改变父组件的状态，而导致数据流的冗余复杂、不易理解，所以 vue 规定了单向数据流，父组件的 prop 更新在子组件中会同时响应，而反过来则不能。
        但是我们依然可以通过 v-model 来实现数据的双向绑定。v-model 一般用在表单绑定数据，如：

        <input v-model="inputValue">

        等同于：

        <input :value="inputValue" @input="data => {inputValue=data}">

        因此，在自定义组件中使用 v-model 指令，那么就意味着：

            i.父组件把 inputValue 数据通过 prop 传递给子组件的 value
            ii.子组件触发 input 事件，并传入子组件最新数据给父组件，父组件给 input 事件绑定一个方法获取到最新的数据
        
        利用 $emit 触发 input 事件：this.$emit('input', value);

        <hello-world v-model="num"></hello-world> => <hello-world :val="num" @change-apple-num="newValue => {num = newValue}"></hello-world>
     -->
    
    <div id="app">
        <!-- <hello-world :val="num" @change-apple-num="val => {num = val}"></hello-world> -->
        <hello-world v-model="num"></hello-world>
        <button @click="doubleAdd">父组件加2苹果</button>
        <div>你买了{{num}}个苹果</div>
    </div>

    <script src="../../node_modules/vue/dist/vue.js"></script>
    <script>
        const HelloWorld = {
            template: `<div class="hello">
                            <button @click="add">子组件加1苹果</button>
                            <div>你买了{{val}}个苹果</div>
                       </div>`,
            model: {
                prop: 'val',
                event: 'change-apple-num'
            },
            props: {
                val: Number
            },
            methods: {
                add() {
                    this.val += 1;
                    this.$emit('change-apple-num', this.val);
                }
            }
        };

        new Vue({
            el: '#app',
            name: 'App',
            components: {
                HelloWorld
            },
            data() {
                return {
                    num: 1,
                }
            },
            methods: {
                doubleAdd(){
                    this.num += 2;
                }
            }
        });
    </script>
</body>
</html>